package net.lzzy;

import java.util.concurrent.*;
import java.util.concurrent.locks.*;


public class ConsumerProducer {
    private static Account account = new Account();

    public static void main(String[] args) {
        // create a thread pool with two threads
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(new DepositTask());
        executor.execute(new WithdrawTask());
        executor.shutdown();

        System.out.println("Thread l\t\tThread 2\t\tBalance");
    }

    // A task for adding an int to the buffer
    private static class DepositTask implements Runnable {
        @Override
        public void run() {
            try {
                while (true) {
                    account.deposit((int)(Math.random() * 10) + 1);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }//        A task for reading and deleting an int from the buffer
    private static class WithdrawTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                account.deposit((int)(Math.random() * 10) + 1);
            }
        }
    }

    // An inner class for buffer
    private static class Account {
        //create a new lock
        private static Lock lock = new ReentrantLock();
        //Create two conditions
        private static Condition newDeposit = lock.newCondition();
        private int balance = 0;
        public int getBalance() {
            return balance;
        }
        public void withdraw(int amount) {
            lock.lock();
            try {
                while (balance < amount) {
                    System.out.println("\t\t\tWait for a deposit");
                    newDeposit.await();
                }
                balance -= amount;
                System.out.println("\t\t\tWithdraw" + amount +
                        "\t\t" + getBalance());
            }
            catch(InterruptedException ex) {
                ex.printStackTrace();
            }
            finally{
                lock.unlock();//Release the lock
            }
        }

        public void deposit(int amount) {
            lock.lock();// Acquire the lock
            try {
                balance += amount;
                System.out.println("Deposit" + amount +
                        "\t\t\t\t\t" + getBalance());
                newDeposit.signalAll();
            } finally {
                lock.unlock(); // Release the lock
            }
        }
    }
}

//    private static Buffer buffer = new Buffer();
//
//    public static void main(String[] args){
//        // Create a thread pool with two threads
//        ExecutorService executor = Executors.newFixedThreadPool(2);
//        executor.execute(new ProducerTask());
//        executor.execute(new ConsumerTask());
//        executor.shutdown();
//    }
//
//    // A task for adding an int to the buffer
//    private static class ProducerTask implements Runnable{
//        public void run(){
//            try{
//                int i = 1;
//                while (true){
//                    System.out.println("Producer writes" + i);
//                    buffer.write(i++);  // add a value to the buffer
//
//                    // put the thread into sleep
//                    Thread.sleep((int)(Math.random()*10000));
//                }
//            }catch (InterruptedException ex){
//                ex.printStackTrace();
//            }
//        }
//    }
//
//    // A task for reading and deleting an ing from the buffer
//    private static class ConsumerTask implements Runnable{
//        public void run(){
//            try{
//                while (true){
//                    System.out.println("\t\t\tComsumer reads" + buffer.read());
//                    // put the thread into sleep
//                    Thread.sleep((int)(Math.random() * 10000));
//                }
//            }catch (InterruptedException ex){
//                ex.printStackTrace();
//            }
//        }
//    }
//
//    // An inner class for buffer
//    private static class Buffer{
//        private static final int CAPACITY = 1; // buffer size
//        private java.util.LinkedList<Integer> queue =
//        new java.util.LinkedList<>();
//
//        // Create a new lock
//        private static Lock lock = new ReentrantLock();
//
//        // create a new conditions
//        private static Condition notEmpty = lock.newCondition();
//        private static Condition notFull = lock.newCondition();
//
//        public void write(int value){
//            lock.lock();  // acquire the lock
//            try{
//                while(queue.size() == CAPACITY){
//                    System.out.println("Wait for notFull condition");
//                    notFull.await();
//                }
//                queue.offer(value);
//                notEmpty.signal();  // Signl notEmpty condition
//            }catch (InterruptedException ex){
//                ex.printStackTrace();
//            }finally{
//                lock.unlock(); // Release the lock
//            }
//        }
//
//        public int read(){
//            int value = 0;
//            lock.lock(); // acquire the lock
//            try{
//                while (queue.isEmpty()){
//                    System.out.println("\t\t\tWait for notEmpty condition");
//                    notEmpty.await();
//                }
//                value = queue.remove();
//                notFull.signal();  // Signl notEull condition
//            }catch(InterruptedException ex){
//                ex.printStackTrace();
//            }finally{
//                lock.unlock(); // release the lock
//                return value;
//            }
//        }
//   }
//}
